<!-- 图片切割并上传 -->
<script lang="ts" setup>
import { ref, nextTick } from 'vue'
import 'cropperjs/dist/cropper.css'
import Cropper from 'cropperjs'
import * as commonApi from '@/api/common'

const emits = defineEmits(['change', 'update:modelValue'])

const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  },
  disabled: {
    type: Boolean,
    default: false
  },
  // 固定宽高比
  aspectRatio: {
    type: Number,
    default: 1
  }
})

// 选择到的图片信息
let curFileInfo: File | null = null
// 图片地址
const imgUrl = ref('')
// 图片选择ref
const fileRef = ref<HTMLInputElement>()
// 裁剪目标
const imgRef = ref<HTMLImageElement>()
// 裁剪预览
const previewRef = ref<HTMLImageElement>()
// Cropper实例
let myCropper: Cropper | null = null

// 弹窗开关
const showDialog = ref(false)

/**
 * 选择图片
 */
function pickClick() {
  fileRef.value?.click()
}
/**
 * 确定裁剪
 */
function confirmClick() {
  //拿到裁剪后的base64的图片
  const base64url = myCropper?.getCroppedCanvas().toDataURL('image/jpeg')
  // base64转文件-如果需要
  const file = dataURLtoFile(base64url, curFileInfo?.name || '')
  // commonApi.uploadFile({ file, fileName: file.name }).then((res) => {
  //   if (res.success) {
  //     const fileId = res.data?.data?.id || ''
  //     const fileUrl = res.data?.data?.url || ''
  //     emits('change', { fileId, fileUrl })
  //     emits('update:modelValue', fileUrl)
  //     showDialog.value = false
  //   }
  // })
}
/**
 * base64转文件
 */
function dataURLtoFile(dataurl: any, filename: any) {
  let arr = dataurl.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]),
    n = bstr.length,
    u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new File([u8arr], filename, {
    type: mime
  })
}
/**
 * 图片选择回调事件
 */
function getImageEvt(event: any) {
  curFileInfo = event.target.files[0] as File
  // 获取 window 的 URL 工具
  const URL = window.URL || window.webkitURL
  // 通过 file 生成目标 url
  imgUrl.value = URL.createObjectURL(curFileInfo)

  nextTick(() => {
    initCropper()
  })
}
/**
 * 初始化Cropper
 */
function initCropper() {
  if (imgRef.value && previewRef.value) {
    // 已存在则销毁重新创建
    if (myCropper) {
      myCropper.destroy()
    }
    myCropper = new Cropper(imgRef.value, {
      // 视图控制
      // 0-无限制
      // 1-限制裁剪框不能超出图片范围
      // 2-限制裁剪框不能超出图片的范围 且图片填充模式为 cover 最长边填充
      // 3-限制裁剪框不能超出图片的范围 且图片填充模式为 contain 最短边填充
      viewMode: 1,
      // 拖拽图片模式
      // crop-形成新的裁剪框
      // move-图片可移动
      // none 什么也没有
      dragMode: 'none',
      // 裁剪框宽高比的初始值 默认与图片宽高比相同 只有在aspectRatio没有设置的情况下可用
      initialAspectRatio: 1,
      // 设置裁剪框为固定的宽高比
      aspectRatio: props.aspectRatio,
      // 预览 设置一个区域容器预览裁剪后的结果 Element, Array (elements), NodeList or String (selector)
      preview: previewRef.value,
      // 是否在容器内显示网格状的背景 默认true
      background: false,
      // 设置裁剪区域占图片的大小 值为 0-1 默认 0.8 表示 80%的区域
      autoCropArea: 0.4,
      // 是否可以通过鼠标滚轮缩放图片 默认true
      zoomOnWheel: false,
      // 检查图片是否跨域 默认true
      // 如果是 会在被复制的图片元素上加上属性crossOrigin 并且在src上加上一个时间戳 避免重加载图片时因为浏览器缓存而加载错误
      checkCrossOrigin: false
      // 之前存储的裁剪后的数据 在初始化时会自动设置 只有在autoCrop设置为true时可用
      // data:
      // 在窗口尺寸调整后 进行响应式的重渲染 默认true
      // responsive: true,
      // 在窗口尺寸调整后 恢复被裁剪的区域 默认true
      // restore: true,
      // 检查图片的方向信息（仅JPEG图片有）默认true 在旋转图片时会对图片方向值做一些处理 以解决IOS设备上的一些问题
      // checkOrientation: true
      // 是否显示图片和裁剪框之间的黑色蒙版 默认true
      // modal: true,
      // 是否显示裁剪框的虚线 默认true
      // guides: true,
      // 是否显示裁剪框中间的 ‘+’ 指示器 默认true
      // center: true,
      // 是否显示裁剪框上面的白色蒙版 （很淡）默认true
      // highlight: true,
      // 允许初始化时自动的裁剪图片 配合 data 使用 默认true
      // autoCrop: true,
      // 是否可以移动图片 默认true
      // movable: true,
      // 是否可以旋转图片 默认true
      // rotatable: true,
      // 是否可以缩放图片（可以改变长宽） 默认true
      // scalable: true,
      // 是否可以缩放图片（改变焦距） 默认true
      // zoomable: true,
      // 是否可以通过拖拽触摸缩放图片 默认true
      // zoomOnTouch: true,
      // 设置鼠标滚轮缩放的灵敏度 默认 0.1
      // wheelZoomRatio: 0.1,
      // 是否可以拖拽裁剪框 默认true
      // cropBoxMovable: true,
      // 是否可以改变裁剪框的尺寸 默认true
      // cropBoxResizable: true,
      // 是否可以通过双击切换拖拽图片模式（move和crop）默认true 当拖拽图片模式为none时不可切换 该设置必须浏览器支持双击事件
      // toggleDragModeOnDblclick: true,
      // 容器、图片、裁剪框的 最小宽高 括号内为默认值 注意 裁剪框的最小高宽是相对与页面而言的 并非相对图片
      // minContainerWidth（200）、minContainerHeight（100）、minCanvasWidth（0）、minCanvasHeight（0）、minCropBoxWidth（0）、minCropBoxHeight（0）
    })
  }
}
/**
 * 打开弹窗
 */
function showClick() {
  if (props.disabled) {
    return
  }
  imgUrl.value = ''
  showDialog.value = true
  if (imgUrl.value) {
    nextTick(() => {
      initCropper()
    })
  }
}
</script>

<template>
  <div class="db-img-clip-bg">
    <div class="db-img-circle" @click="showClick">
      <DbImage :src="modelValue" />
      <div class="db-img-circle-mask" v-if="!disabled">选择图片</div>
    </div>
    <!-- 弹窗 -->
    <dui-dialog v-model="showDialog" title="裁剪图片">
      <div class="db-clip-body">
        <!-- 原图片 -->
        <div class="db-origin-img-box">
          <img ref="imgRef" :src="imgUrl" v-show="imgUrl" style="width: 100%; height: 100%" />
        </div>
        <div class="db-right-box">
          <div class="db-preview-box">
            <div>裁剪预览</div>
            <div class="db-preview-item" ref="previewRef"></div>
            <div>150 x 150</div>
          </div>
          <!-- 按钮 -->
          <div class="db-btn-box">
            <el-button type="primary" @click="pickClick">选择图片</el-button>
            <el-button style="margin: 10px 0 0 0" type="primary" @click="confirmClick">确定裁剪</el-button>
          </div>
        </div>
      </div>
      <!-- 只用input来实现上传，但是不显示input -->
      <input v-show="false" ref="fileRef" accept="image/png, image/jpeg" type="file" @change="getImageEvt" />
    </dui-dialog>
  </div>
</template>

<style lang="scss" scoped>
.db-img-clip-bg {
  .db-img-circle {
    position: relative;
    width: 100px;
    height: 100px;
    border: 1px solid lightgray;
    box-sizing: border-box;
    border-radius: 50%;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    .db-img-circle-mask {
      position: absolute;
      left: 0;
      top: 0;
      cursor: pointer;
      display: none;
      align-items: center;
      justify-content: center;
      width: 99px;
      height: 99px;
      color: white;
      background-color: rgba($color: #000000, $alpha: 0.3);
    }
  }
  .db-img-circle:hover {
    .db-img-circle-mask {
      display: flex;
    }
  }
}
.db-clip-body {
  display: flex;
  .db-origin-img-box {
    width: 500px;
    height: 350px;
    border: 1px solid lightgray;
    box-sizing: border-box;
    overflow: hidden;
  }
  .db-right-box {
    width: 200px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    .db-preview-box {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      .db-preview-item {
        width: 150px;
        height: 150px;
        overflow: hidden;
        border-radius: 50%;
        border: 1px solid lightgray;
        box-sizing: border-box;
        margin: 10px 0;
      }
    }
    .db-btn-box {
      display: flex;
      flex-direction: column;
      align-items: center;
    }
  }
}
</style>
